/**
 * Copyright  2025, Hai Yue Xing He  ZHAO LIMIN
 *
 * @author        ZHAO LIMIN
 * @version       1.0.1
 * @since         2025-04
 * public static ts   A 4D Cartesian point.
 */
import { Check } from './Check'
import { defined } from './Defined'
import { DeveloperError } from './DeveloperError'
import { HYXHMathUtil } from './HYXHMathUtil'
import { defaultValue } from './HYXHDefaultValue'
import { Color } from './Color'

import { IPackable, packs, unpacks, packArray, unpackArray } from './Packable'
import { UNION_NUMBER_ARRAY } from './HDataType'
import { Quaternion } from './Quaternion'
import { ICartesian } from './Cartesian'
import { IArrayIndex, INumberArray } from './HXArray'

export interface ICartesian4D extends ICartesian  {
  x: number
  y: number
  z: number
  w: number
}
export class Cartesian4 implements ICartesian4D, IPackable, INumberArray, IArrayIndex {
  [index: number]: number; 
  public get x(): number {
    return this[0]
  }
  public set x(v:number) {
    this[0] = v??0.0
  }
  //public y: number
  public get y(): number {
    return this[1]
  }
  public set y(v:number) {
    this[1] = v??0.0
  }

  public get z(): number {
    return this[2]
  }
  public set z(v:number) {
    this[2] = v??0.0
  }
  public get w(): number {
    return this[3]
  }
  public set w(v:number) {
    this[3] = v??0.0
  }
  
  public get length(): number {
    return Cartesian4.packedLength 
  }
  
  /**
   * A 3D Cartesian point.
   * @alias Cartesian4
   * @constructor
   *
   * @param {number} [x=0.0] The X component.
   * @param {number} [y=0.0] The Y component.
   * @param {number} [z=0.0] The Z component.
   *
   * @see Cartesian2
   * @see Cartesian4
   * @see Packable
   */
  constructor(x?: number, y?: number, z?: number, w?: number) {
    /**
     * The X component.
     * @type {number}
     * @default 0.0
     */
    this.x = x ?? 0.0

    /**
     * The Y component.
     * @type {number}
     * @default 0.0
     */
    this.y = y ?? 0.0

    /**
     * The Z component.
     * @type {number}
     * @default 0.0
     */
    this.z = z ?? 0.0
    /**
     * The W component.
     * @type {number}
     * @default 0.0
     */
    this.w = w ?? 0.0
  } 

  push(...items: number[]): number[] {
    this[0] = items[0]
    this[1] = items[1]
    this[2] = items[2]
    this[3] = items[3]
    return [this[0], this[1], this[2], this[3]]
  }

  /**
   * Creates a Cartesian4 instance from x, y, z and w coordinates.
   *
   * @param {number} x The x coordinate.
   * @param {number} y The y coordinate.
   * @param {number} z The z coordinate.
   * @param {number} w The w coordinate.
   * @param {Cartesian4} [result] The object onto which to store the result.
   * @returns {Cartesian4} The modified result parameter or a new Cartesian4 instance if one was not provided.
   */
  public static fromElements(
    x: number,
    y: number,
    z: number,
    w: number,
    result?: ICartesian,
  ): ICartesian | undefined {
    if (!defined(result)) {
      return new Cartesian4(x, y, z, w)
    }
    result!.x = x
    result!.y = y
    result!.z = z
    result!.w = w
    return result
  }  
  /**
   * Creates a Cartesian4 instance from a {@link Color}. <code>red</code>, <code>green</code>, <code>blue</code>,
   * and <code>alpha</code> map to <code>x</code>, <code>y</code>, <code>z</code>, and <code>w</code>, respectively.
   *
   * @param {Color} color The source color.
   * @param {Cartesian4} [result] The object onto which to store the result.
   * @returns {Cartesian4} The modified result parameter or a new Cartesian4 instance if one was not provided.
   */
  public static fromColor(color: Color, result?: ICartesian): ICartesian | undefined {
    //>>includeStart('debug', pragmas.debug);
    Check.typeOf.object('color', color)
    //>>includeEnd('debug');
    if (!defined(result)) {
      return new Cartesian4(color.red, color.green, color.blue, color.alpha)
    }

    result!.x = color.red
    result!.y = color.green
    result!.z = color.blue
    result!.w = color.alpha
    return result
  }
  /**
   * Duplicates a Cartesian4 instance.
   *
   * @param {Cartesian4} cartesian The Cartesian to duplicate.
   * @param {Cartesian4} [result] The object onto which to store the result.
   * @returns {Cartesian4} The modified result parameter or a new Cartesian4 instance if one was not provided. (Returns undefined if cartesian is undefined)
   */
  public static clone(cartesian: ICartesian, result?: ICartesian): ICartesian | undefined {
    if (!defined(cartesian)) {
      return undefined
    }

    if (!defined(result)) {
      return new Cartesian4(cartesian.x, cartesian.y, cartesian.z, cartesian.w)
    }

    result!.x = cartesian.x
    result!.y = cartesian.y
    result!.z = cartesian.z
    result!.w = cartesian.w
    return result
  }
  /**
   * The number of elements used to pack the object into an array.
   * @type {number}
   */
  public static readonly packedLength = 4
  /**
   * @override IPackable
   * @returns
   * @see Packable.IPackable
   */
  public getPackedLength(): number {
    return Cartesian4.packedLength
  }
  public getRowLength(): number {
    return 1
  }
  public getColumnLength(): number {
    return Cartesian4.packedLength
  }
  /**
   * Stores the provided instance into the provided array.
   *
   * @param {Cartesian4} value The value to pack.
   * @param {number[]} array The array to pack into.
   * @param {number} [startingIndex=0] The index into the array at which to start packing the elements.
   *
   * @returns {number[]} The array that was packed into
   */
  public static pack(
    value: ICartesian,
    array: UNION_NUMBER_ARRAY,
    startingIndex: number = 0,
  ): UNION_NUMBER_ARRAY | undefined {
    //>>includeStart('debug', pragmas.debug);
    Check.typeOf.object('value', value)
    Check.defined('array', array)
    //>>includeEnd('debug');
    startingIndex = startingIndex ?? 0
    packs(value as Cartesian4, array, startingIndex)
    return array
  }
  /**
   * Stores the provided instance into the provided array.
   *
   * @param {number[]} array The array to pack into.
   * @param {number} [startingIndex=0] The index into the array at which to start packing the elements.
   *
   */
  public pack(
    array: UNION_NUMBER_ARRAY,
    startingIndex: number = 0) {
    //>>includeStart('debug', pragmas.debug);
    Check.typeOf.object('array', array)
    Check.defined('array', array)
    Check.typeOf.tnumber.checkInteger('startingIndex', startingIndex)
    //>>includeEnd('debug');
    startingIndex = startingIndex ?? 0
    array[startingIndex++] = this.x
    array[startingIndex++] = this.y
    array[startingIndex++] = this.z
    array[startingIndex] = this.w
    return array
  }
  /**
   * Retrieves an instance from a packed array.
   *
   * @param {number[]} array The packed array.
   * @param {number} [startingIndex=0] The starting index of the element to be unpacked.
   * @param {Cartesian4} [result] The object into which to store the result.
   * @returns {Cartesian4}  The modified result parameter or a new Cartesian4 instance if one was not provided.
   */
  public static unpack(
    array: UNION_NUMBER_ARRAY,
    startingIndex: number,
    result?: ICartesian,
  ): ICartesian | undefined {
    //>>includeStart('debug', pragmas.debug);
    Check.defined('array', array)
    //>>includeEnd('debug');
    startingIndex = startingIndex ?? 0
    if (!defined(result)) {
      result = new Cartesian4()
    }
    result = unpacks(array, startingIndex, result as Cartesian4) as Cartesian4
    return result
  }
  /**
   * Retrieves an instance from a packed array.
   *
   * @param {number[]} array The packed array.
   * @param {number} [startingIndex=0] The starting index of the element to be unpacked.
   */
  public unpack(
    array: UNION_NUMBER_ARRAY,
    startingIndex: number = 0) {
    //>>includeStart('debug', pragmas.debug);
    Check.defined('array', array)
    //>>includeEnd('debug');
    startingIndex = startingIndex ?? 0
    this.x = array[startingIndex++]
    this.y = array[startingIndex++]
    this.z = array[startingIndex++]
    this.w = array[startingIndex]
  }
  /**
   * 将一个Cartesian4数组展平为一个组件数组。
   *
   * @param {Cartesian4[]} array The array of cartesians to pack.
   * @param {number[]} [result] The array onto which to store the result. If this is a typed array, it must have
   * array.length * 4 components, else a {@link DeveloperError} will be thrown. If it is a regular array, it will be
   * resized to have (array.length * 4) elements.
   * @returns {number[]} The packed array.
   */
  public static packArray(
    array: Array<ICartesian>,
    result: UNION_NUMBER_ARRAY, startIndex: number = 0): UNION_NUMBER_ARRAY {
    //>>includeStart('debug', pragmas.debug);
    Check.defined('array', array)
    //>>includeEnd('debug');

    const length = array.length
    const resultLength = length * Cartesian4.packedLength
    if (!defined(result)) {
      result = new Array(resultLength)
    } else if (!Array.isArray(result)) {
      //>>includeStart('debug', pragmas.debug);
      throw new DeveloperError(
        'If result is a typed array, it must have exactly array.length * 4 elements',
      )
      //>>includeEnd('debug');
    } else if (result.length !== resultLength) {
      result.length = resultLength
    }
    packArray(array as Cartesian4[], result, startIndex)
    return result
  }

  /**
   * Unpacks an array of cartesian components into an array of Cartesian4s.
   *
   * @param {number[]} array The array of components to unpack.
   * @param {Cartesian4[]} [result] The array onto which to store the result.
   * @returns {Cartesian4[]} The unpacked array.
   */
  public static unpackArray(
    array: UNION_NUMBER_ARRAY,
    result: Array<ICartesian>): Array<ICartesian> {
    //>>includeStart('debug', pragmas.debug);
    Check.defined('array', array)
    Check.typeOf.tnumber.greaterThanOrEquals('array.length', array.length, 4)
    if (array.length % Cartesian4.packedLength !== 0) {
      throw new DeveloperError('array length must be a multiple of 4.')
    }
    //>>includeEnd('debug');
    const length = array.length
    if (!defined(result)) {
      result = new Array(length / Cartesian4.packedLength)
      for (let i = 0; i < result.length; ++i) {
        result[i] = new Cartesian4()
      }
    } else {
      result.length = length / Cartesian4.packedLength
    }

    unpackArray(array, result as Cartesian4[])
    return result
  }

  /**
   * Creates a Cartesian4 from four consecutive elements in an array.
   * @function
   *
   * @param {number[]} array The array whose four consecutive elements correspond to the x, y, z, and w components,
   * respectively.
   * @param {number} [startingIndex=0] The offset into the array of the first element, which corresponds to the x
   * component.
   * @param {Cartesian4} [result] The object onto which to store the result.
   * @returns {Cartesian4}  The modified result parameter or a new Cartesian4 instance if one was not provided.
   *
   * @example
   * // Create a Cartesian4 with (1.0, 2.0, 3.0, 4.0)
   * const v = [1.0, 2.0, 3.0, 4.0];
   * const p = Cartesian4.fromArray(v);
   *
   * // Create a Cartesian4 with (1.0, 2.0, 3.0, 4.0) using an offset into an array
   * const v2 = [0.0, 0.0, 1.0, 2.0, 3.0, 4.0];
   * const p2 = Cartesian4.fromArray(v2, 2);
   */
  public static readonly fromArray = Cartesian4.unpack
  /**
   * Computes the value of the maximum component for the supplied Cartesian.
   *
   * @param {Cartesian4} cartesian The cartesian to use.
   * @returns {number} The value of the maximum component.
   */
  public static maximumComponent(cartesian: ICartesian): number {
    //>>includeStart('debug', pragmas.debug);
    Check.typeOf.object('cartesian', cartesian)
    //>>includeEnd('debug');

    return Math.max(cartesian.x, cartesian.y, cartesian.z!, cartesian.w!)
  }
  /**
   * Computes the value of the minimum component for the supplied Cartesian.
   *
   * @param {Cartesian4} cartesian The cartesian to use.
   * @returns {number} The value of the minimum component.
   */
  public static minimumComponent(cartesian: ICartesian): number {
    //>>includeStart('debug', pragmas.debug);
    Check.typeOf.object('cartesian', cartesian)
    //>>includeEnd('debug');

    return Math.min(cartesian.x, cartesian.y, cartesian.z!, cartesian.w!)
  }
  /**
   * Compares two Cartesians and computes a Cartesian which contains the minimum components of the supplied Cartesians.
   *
   * @param {Cartesian4} first A cartesian to compare.
   * @param {Cartesian4} second A cartesian to compare.
   * @param {Cartesian4} result The object into which to store the result.
   * @returns {Cartesian4} A cartesian with the minimum components.
   */
  public static minimumByComponent(
    first: ICartesian,
    second: ICartesian,
    result?: ICartesian): ICartesian | undefined {
    //>>includeStart('debug', pragmas.debug);
    Check.typeOf.object('first', first)
    Check.typeOf.object('second', second)
    Check.typeOf.object('result', result)
    //>>includeEnd('debug');
    if (!defined(result)) {
        result = new Cartesian4()
    }
    result!.x = Math.min(first.x, second.x)
    result!.y = Math.min(first.y, second.y)
    result!.z = Math.min(first.z!, second.z!)
    result!.w = Math.min(first.w!, second.w!)

    return result
  }
  /**
   * Compares two Cartesians and computes a Cartesian which contains the maximum components of the supplied Cartesians.
   *
   * @param {Cartesian4} first A cartesian to compare.
   * @param {Cartesian4} second A cartesian to compare.
   * @param {Cartesian4} result The object into which to store the result.
   * @returns {Cartesian4} A cartesian with the maximum components.
   */
  public static maximumByComponent(
    first: ICartesian,
    second: ICartesian,
    result?: ICartesian): ICartesian | undefined {
    //>>includeStart('debug', pragmas.debug);
    Check.typeOf.object('first', first)
    Check.typeOf.object('second', second)
    Check.typeOf.object('result', result)
    //>>includeEnd('debug');
    if (!defined(result)) {
        result = new Cartesian4()
    }
    result!.x = Math.max(first.x, second.x)
    result!.y = Math.max(first.y, second.y)
    result!.z = Math.max(first.z!, second.z!)
    result!.w = Math.max(first.w!, second.w!)

    return result
  }
  /**
   * 将值限制在两个值之间。
   *
   * @param {Cartesian4} value The value to clamp.
   * @param {Cartesian4} min The minimum bound.
   * @param {Cartesian4} max The maximum bound.
   * @param {Cartesian4} result The object into which to store the result.
   * @returns {Cartesian4} The clamped value such that min <= result <= max.
   */
  public static clamp(
    value: ICartesian,
    min: ICartesian,
    max: ICartesian,
    result?: ICartesian): ICartesian | undefined {
    //>>includeStart('debug', pragmas.debug);
    Check.typeOf.object('value', value)
    Check.typeOf.object('min', min)
    Check.typeOf.object('max', max)
    Check.typeOf.object('result', result)
    //>>includeEnd('debug');
    if (!defined(result)) {
        result = new Cartesian4()
    }
    const x = HYXHMathUtil.clamp(value.x, min.x, max.x)
    const y = HYXHMathUtil.clamp(value.y, min.y, max.y)
    const z = HYXHMathUtil.clamp(value.z!, min.z!, max.z!)
    const w = HYXHMathUtil.clamp(value.w!, min.w!, max.w!)
    result!.x = x
    result!.y = y
    result!.z = z
    result!.w = w
    return result
  }
  /**
   * Computes the provided Cartesian's squared magnitude.
   *
   * @param {Cartesian4} cartesian The Cartesian instance whose squared magnitude is to be computed.
   * @returns {number} The squared magnitude.
   */
  public static magnitudeSquared(cartesian: ICartesian): number {
    //>>includeStart('debug', pragmas.debug);
    Check.typeOf.object('cartesian', cartesian)
    //>>includeEnd('debug');
    return (
      cartesian.x * cartesian.x +
      cartesian.y * cartesian.y +
      cartesian.z! * cartesian.z! +
      cartesian.w! * cartesian.w!
    )
  }
  /**
   * Computes the Cartesian's magnitude (length).
   *
   * @param {Cartesian4} cartesian The Cartesian instance whose magnitude is to be computed.
   * @returns {number} The magnitude.
   */
  public static magnitude(cartesian: ICartesian): number {
    return Math.sqrt(Cartesian4.magnitudeSquared(cartesian))
  }

  public static readonly distanceScratch = new Cartesian4()

  /**
   * Computes the 4-space distance between two points.
   *
   * @param {Cartesian4} left The first point to compute the distance from.
   * @param {Cartesian4} right The second point to compute the distance to.
   * @returns {number} The distance between two points.
   *
   * @example
   * // Returns 1.0
   * const d = Cartesian4.distance(
   *   new Cartesian4(1.0, 0.0, 0.0, 0.0),
   *   new Cartesian4(2.0, 0.0, 0.0, 0.0));
   */
  public static distance(left: ICartesian, right: ICartesian): number {
    //>>includeStart('debug', pragmas.debug);
    Check.typeOf.object('left', left)
    Check.typeOf.object('right', right)
    //>>includeEnd('debug');

    Cartesian4.subtract(left, right, Cartesian4.distanceScratch)
    return Cartesian4.magnitude(Cartesian4.distanceScratch)
  }

  /**
   * Computes the squared distance between two points.  Comparing squared distances
   * using this function is more efficient than comparing distances using {@link Cartesian4#distance}.
   *
   * @param {Cartesian4} left The first point to compute the distance from.
   * @param {Cartesian4} right The second point to compute the distance to.
   * @returns {number} The distance between two points.
   *
   * @example
   * // Returns 4.0, not 2.0
   * const d = Cartesian4.distance(
   *   new Cartesian4(1.0, 0.0, 0.0, 0.0),
   *   new Cartesian4(3.0, 0.0, 0.0, 0.0));
   */
  public static distanceSquared(left: ICartesian, right: ICartesian): number {
    //>>includeStart('debug', pragmas.debug);
    Check.typeOf.object('left', left)
    Check.typeOf.object('right', right)
    //>>includeEnd('debug');

    Cartesian4.subtract(left, right, Cartesian4.distanceScratch)
    return Cartesian4.magnitudeSquared(Cartesian4.distanceScratch)
  }
  /**
   * 计算提供的笛卡尔坐标系的归一化形式。
   *
   * @param {Cartesian4} cartesian The Cartesian to be normalized.
   * @param {Cartesian4} result The object onto which to store the result.
   * @returns {Cartesian4} The modified result parameter.
   */
  public static normalize(
    cartesian: ICartesian,
    result?: ICartesian): ICartesian | undefined {
    //>>includeStart('debug', pragmas.debug);
    Check.typeOf.object('cartesian', cartesian)
    Check.typeOf.object('result', result)
    //>>includeEnd('debug');
    if (!defined(result)) {
        result = new Cartesian4()
    }
    const magnitude = Cartesian4.magnitude(cartesian)

    result!.x = cartesian.x / magnitude
    result!.y = cartesian.y / magnitude
    result!.z = cartesian.z! / magnitude
    result!.w = cartesian.w! / magnitude

    //>>includeStart('debug', pragmas.debug);
    if (isNaN(result!.x) || isNaN(result!.y) || isNaN(result!.z) || isNaN(result!.w)) {
      throw new DeveloperError('normalized result is not a number')
    }
    //>>includeEnd('debug');

    return result
  }
  /**
   * 计算两个笛卡尔坐标系的点积（标量积）。
   *
   * @param {Cartesian4} left The first Cartesian.
   * @param {Cartesian4} right The second Cartesian.
   * @returns {number} The dot product.
   */
  public static dot(left: ICartesian, right: ICartesian): number {
    //>>includeStart('debug', pragmas.debug);
    Check.typeOf.object('left', left)
    Check.typeOf.object('right', right)
    //>>includeEnd('debug');
    return left.x * right.x + left.y * right.y + left.z! * right.z! + left.w! * right.w!
  }
  /**
   *
   * 计算两个笛卡尔坐标系的分量乘积。
   * @param {Cartesian4} left The first Cartesian.
   * @param {Cartesian4} right The second Cartesian.
   * @param {Cartesian4} result The object onto which to store the result.
   * @returns {Cartesian4} The modified result parameter.
   */
  public static multiplyComponents(
    left: ICartesian,
    right: ICartesian,
    result?: ICartesian): ICartesian | undefined {
    //>>includeStart('debug', pragmas.debug);
    Check.typeOf.object('left', left)
    Check.typeOf.object('right', right)
    Check.typeOf.object('result', result)
    //>>includeEnd('debug');
    if (!defined(result)) {
        result = new Cartesian4()
    }
    result!.x = left.x * right.x
    result!.y = left.y * right.y
    result!.z = left.z! * right.z!
    result!.w = left.w! * right.w!
    return result
  }
  /**
   * 计算两个笛卡尔坐标系的分量商。
   *
   * @param {Cartesian4} left The first Cartesian.
   * @param {Cartesian4} right The second Cartesian.
   * @param {Cartesian4} result The object onto which to store the result.
   * @returns {Cartesian4} The modified result parameter.
   */
  public static divideComponents(
    left: ICartesian,
    right: ICartesian,
    result?: ICartesian): ICartesian | undefined {
    //>>includeStart('debug', pragmas.debug);
    Check.typeOf.object('left', left)
    Check.typeOf.object('right', right)
    Check.typeOf.object('result', result)
    //>>includeEnd('debug');
    if (!defined(result)) {
        result = new Cartesian4()
    }
    result!.x = left.x / right.x
    result!.y = left.y / right.y
    result!.z = left.z! / right.z!
    result!.w = left.w! / right.w!
    return result
  }
  /**
   *计算两个笛卡尔坐标系的分量和。
   *
   * @param {Cartesian4} left The first Cartesian.
   * @param {Cartesian4} right The second Cartesian.
   * @param {Cartesian4} result The object onto which to store the result.
   * @returns {Cartesian4} The modified result parameter.
   */
  public static add(
    left: ICartesian, right: ICartesian,
    result?: ICartesian): ICartesian | undefined {
    //>>includeStart('debug', pragmas.debug);
    Check.typeOf.object('left', left)
    Check.typeOf.object('right', right)
    Check.typeOf.object('result', result)
    //>>includeEnd('debug');
    if (!defined(result)) {
        result = new Cartesian4()
    }
    result!.x = left.x + right.x
    result!.y = left.y + right.y
    result!.z = left.z! + right.z!
    result!.w = left.w! + right.w!
    return result
  }
  /**
   *
   * 计算两个笛卡尔坐标系的分量差。
   *
   * @param {Cartesian4} left The first Cartesian.
   * @param {Cartesian4} right The second Cartesian.
   * @param {Cartesian4} result The object onto which to store the result.
   * @returns {Cartesian4} The modified result parameter.
   */
  public static subtract(
    left: ICartesian, right: ICartesian,
    result?: ICartesian): ICartesian | undefined {
    //>>includeStart('debug', pragmas.debug);
    Check.typeOf.object('left', left)
    Check.typeOf.object('right', right)
    Check.typeOf.object('result', result)
    //>>includeEnd('debug');
    if (!defined(result)) {
        result = new Cartesian4()
    }
    result!.x = left.x - right.x
    result!.y = left.y - right.y
    result!.z = left.z! - right.z!
    result!.w = left.w! - right.w!
    return result
  }

  /**
   * 将提供的笛卡尔分量与提供的标量逐个相乘。
   *
   * @param {Cartesian4} cartesian The Cartesian to be scaled.
   * @param {number} scalar The scalar to multiply with.
   * @param {Cartesian4} result The object onto which to store the result.
   * @returns {Cartesian4} The modified result parameter.
   */
  public static multiplyByScalar(
    cartesian: ICartesian,
    scalar: number,
    result?: ICartesian): ICartesian | undefined {
    //>>includeStart('debug', pragmas.debug);
    Check.typeOf.object('cartesian', cartesian)
    Check.typeOf.number('scalar', scalar)
    Check.typeOf.object('result', result)
    //>>includeEnd('debug');
    if (!defined(result)) {
        result = new Cartesian4()
    }
    result!.x = cartesian.x * scalar
    result!.y = cartesian.y * scalar
    result!.z = cartesian.z! * scalar
    result!.w = cartesian.w! * scalar
    return result
  }

  /**
   * 将提供的笛卡尔分量除以提供的标量。
   *
   * @param {Cartesian4} cartesian The Cartesian to be divided.
   * @param {number} scalar The scalar to divide by.
   * @param {Cartesian4} result The object onto which to store the result.
   * @returns {Cartesian4} The modified result parameter.
   */
  public static divideByScalar(
    cartesian: ICartesian,
    scalar: number,
    result?: ICartesian): ICartesian | undefined {
    //>>includeStart('debug', pragmas.debug);
    Check.typeOf.object('cartesian', cartesian)
    Check.typeOf.number('scalar', scalar)
    Check.typeOf.object('result', result)
    //>>includeEnd('debug');
    if (!defined(result)) {
        result = new Cartesian4()
    }
    result!.x = cartesian.x / scalar
    result!.y = cartesian.y / scalar
    result!.z = cartesian.z! / scalar
    result!.w = cartesian.w! / scalar
    return result
  }
  /**
   * 否定了提供的笛卡尔坐标系。(反向/负向 赋值)
   *
   * @param {Cartesian4} cartesian The Cartesian to be negated.
   * @param {Cartesian4} result The object onto which to store the result.
   * @returns {Cartesian4} The modified result parameter.
   */
  public static negate(
    cartesian: ICartesian,
    result?: ICartesian): ICartesian | undefined {
    //>>includeStart('debug', pragmas.debug);
    Check.typeOf.object('cartesian', cartesian)
    Check.typeOf.object('result', result)
    //>>includeEnd('debug');
    if (!defined(result)) {
        result = new Cartesian4()
    }
    result!.x = -cartesian.x
    result!.y = -cartesian.y
    result!.z = -cartesian.z!
    result!.w = -cartesian.w!
    return result
  }
  /**
   * 计算提供的笛卡尔坐标的绝对值。
   *
   * @param {Cartesian4} cartesian The Cartesian whose absolute value is to be computed.
   * @param {Cartesian4} result The object onto which to store the result.
   * @returns {Cartesian4} The modified result parameter.
   */
  public static abs(
    cartesian: ICartesian,
    result?: ICartesian): ICartesian | undefined {
    //>>includeStart('debug', pragmas.debug);
    Check.typeOf.object('cartesian', cartesian)
    Check.typeOf.object('result', result)
    //>>includeEnd('debug');
    if (!defined(result)) {
        result = new Cartesian4()
    }
    result!.x = Math.abs(cartesian.x)
    result!.y = Math.abs(cartesian.y)
    result!.z = Math.abs(cartesian.z!)
    result!.w = Math.abs(cartesian.w!)
    return result
  }

  public static readonly lerpScratch = new Cartesian4()
  /**
   * 使用提供的笛卡尔坐标计算t处的线性插值或外推。
   *
   * @param {Cartesian4} start The value corresponding to t at 0.0.
   * @param {Cartesian4}end The value corresponding to t at 1.0.
   * @param {number} t The point along t at which to interpolate.
   * @param {Cartesian4} result The object onto which to store the result.
   * @returns {Cartesian4} The modified result parameter.
   */
  public static lerp(
    start: ICartesian,
    end: ICartesian,
    t: number,
    result?: ICartesian): ICartesian | undefined {
    //>>includeStart('debug', pragmas.debug);
    Check.typeOf.object('start', start)
    Check.typeOf.object('end', end)
    Check.typeOf.number('t', t)
    Check.typeOf.object('result', result)
    //>>includeEnd('debug');
    if (!defined(result)) {
        result = new Cartesian4()
    }
    Cartesian4.multiplyByScalar(end, t, Cartesian4.lerpScratch)
    result = Cartesian4.multiplyByScalar(start, 1.0 - t, result)
    return Cartesian4.add(Cartesian4.lerpScratch, result as Cartesian4, result)
  }

  public static readonly mostOrthogonalAxisScratch = new Cartesian4()
  /**
   *
   * 返回与提供的笛卡尔坐标系最正交的轴。
   * @param {Cartesian4} cartesian The Cartesian on which to find the most orthogonal axis.
   * @param {Cartesian4} result The object onto which to store the result.
   * @returns {Cartesian4} The most orthogonal axis.
   */
  public static mostOrthogonalAxis(
    cartesian: ICartesian,
    result?: ICartesian): ICartesian | undefined {
    //>>includeStart('debug', pragmas.debug);
    Check.typeOf.object('cartesian', cartesian)
    Check.typeOf.object('result', result)
    //>>includeEnd('debug');
    if (!defined(result)) {
        result = new Cartesian4()
    }
    const f = Cartesian4.normalize(cartesian, Cartesian4.mostOrthogonalAxisScratch)
    Cartesian4.abs(f!, f)

    if (f!.x <= f!.y) {
      if (f!.x <= f!.z!) {
        if (f!.x <= f!.w!) {
          result = defaultValue<Cartesian4>(
            Cartesian4.clone(Cartesian4.UNIT_X, result) as Cartesian4,
            new Cartesian4(1.0, 0, 0, 0),
          )
        } else {
          result = defaultValue<Cartesian4>(
            Cartesian4.clone(Cartesian4.UNIT_W, result) as Cartesian4,
            new Cartesian4(0, 0, 0, 1.0),
          )
        }
      } else if (f!.z! <= f!.w!) {
        result = defaultValue<Cartesian4>(
          Cartesian4.clone(Cartesian4.UNIT_Z, result) as Cartesian4,
          new Cartesian4(0, 0, 1.0, 0),
        )
      } else {
        result = defaultValue<Cartesian4>(
          Cartesian4.clone(Cartesian4.UNIT_W, result) as Cartesian4,
          new Cartesian4(0, 0, 0, 1.0),
        )
      }
    } else if (f!.y <= f!.z!) {
      if (f!.y <= f!.w!) {
        result = defaultValue<Cartesian4>(
          Cartesian4.clone(Cartesian4.UNIT_Y, result) as Cartesian4,
          new Cartesian4(0, 1.0, 0, 0),
        )
      } else {
        result = defaultValue<Cartesian4>(
          Cartesian4.clone(Cartesian4.UNIT_W, result) as Cartesian4,
          new Cartesian4(0, 0, 0, 1.0),
        )
      }
    } else if (f!.z! <= f!.w!) {
      result = defaultValue<Cartesian4>(
        Cartesian4.clone(Cartesian4.UNIT_Z, result) as Cartesian4,
        new Cartesian4(0, 0, 1.0, 0),
      )
    } else {
      result = defaultValue<Cartesian4>(
        Cartesian4.clone(Cartesian4.UNIT_W, result) as Cartesian4,
        new Cartesian4(1.0, 0, 0, 1.0),
      )
    }
    return result
  }
  /**
   * 按分量比较提供的Cartesian坐标，并返回
   * <code>true</code> if they are equal, <code>false</code> otherwise.
   *
   * @param {Cartesian4} [left] The first Cartesian.
   * @param {Cartesian4} [right] The second Cartesian.
   * @returns {boolean} <code>true</code> if left and right are equal, <code>false</code> otherwise.
   */
  public static equals(left: ICartesian, right: ICartesian): boolean {
    return (
      left === right ||
      (defined(left) &&
        defined(right) &&
        left.x === right.x &&
        left.y === right.y &&
        left.z === right.z &&
        left.w === right.w)
    )
  }
  /**
   * @private
   */
  public static equalsArray(cartesian: ICartesian, array: Array<number>, offset: number): boolean {
    return (
      cartesian.x === array[offset] &&
      cartesian.y === array[offset + 1] &&
      cartesian.z === array[offset + 2] &&
      cartesian.w === array[offset + 3]
    )
  }
  /**
   * Compares the provided Cartesians componentwise and returns
   * <code>true</code> if they pass an absolute or relative tolerance test,
   * <code>false</code> otherwise.
   *
   * @param {Cartesian4} [left] The first Cartesian.
   * @param {Cartesian4} [right] The second Cartesian.
   * @param {number} [relativeEpsilon=0] The relative epsilon tolerance to use for equality testing.
   * @param {number} [absoluteEpsilon=relativeEpsilon] The absolute epsilon tolerance to use for equality testing.
   * @returns {boolean} <code>true</code> if left and right are within the provided epsilon, <code>false</code> otherwise.
   */
  public static equalsEpsilon(
    left: ICartesian,
    right: ICartesian,
    relativeEpsilon: number,
    absoluteEpsilon: number,
  ): boolean {
    return (
      left === right ||
      (defined(left) &&
        defined(right) &&
        HYXHMathUtil.equalsEpsilon(left.x, right.x, relativeEpsilon, absoluteEpsilon) &&
        HYXHMathUtil.equalsEpsilon(left.y, right.y, relativeEpsilon, absoluteEpsilon) &&
        HYXHMathUtil.equalsEpsilon(left.z!, right.z!, relativeEpsilon, absoluteEpsilon) &&
        HYXHMathUtil.equalsEpsilon(left.w!, right.w!, relativeEpsilon, absoluteEpsilon))
    )
  }
  /**
   * An immutable Cartesian4 instance initialized to (0.0, 0.0, 0.0, 0.0).
   *
   * @type {Cartesian4}
   * @constant
   */
  public static readonly ZERO = Object.freeze(new Cartesian4(0.0, 0.0, 0.0, 0.0))
  /**
   * An immutable Cartesian4 instance initialized to (1.0, 1.0, 1.0, 1.0).
   *
   * @type {Cartesian4}
   * @constant
   */
  public static readonly ONE = Object.freeze(new Cartesian4(1.0, 1.0, 1.0, 1.0))
  /**
   * An immutable Cartesian4 instance initialized to (1.0, 0.0, 0.0, 0.0).
   *
   * @type {Cartesian4}
   * @constant
   */
  public static readonly UNIT_X = Object.freeze(new Cartesian4(1.0, 0.0, 0.0, 0.0))
  /**
   * An immutable Cartesian4 instance initialized to (0.0, 1.0, 0.0, 0.0).
   *
   * @type {Cartesian4}
   * @constant
   */
  public static readonly UNIT_Y = Object.freeze(new Cartesian4(0.0, 1.0, 0.0, 0.0))
  /**
   * An immutable Cartesian4 instance initialized to (0.0, 0.0, 1.0, 0.0).
   *
   * @type {Cartesian4}
   * @constant
   */
  public static readonly UNIT_Z = Object.freeze(new Cartesian4(0.0, 0.0, 1.0, 0.0))
  /**
   * An immutable Cartesian4 instance initialized to (0.0, 0.0, 0.0, 1.0).
   *
   * @type {Cartesian4}
   * @constant
   */
  public static readonly UNIT_W = Object.freeze(new Cartesian4(0.0, 0.0, 0.0, 1.0))

  /**
   * 复制此Cartesian4实例。
   *
   * @param {Cartesian4} [result] The object onto which to store the result.
   * @returns {Cartesian4} The modified result parameter or a new Cartesian4 instance if one was not provided.
   */
  public clone(result?: ICartesian): ICartesian | undefined {
    return Cartesian4.clone(this, result)
  }

  /**
   * Compares this Cartesian against the provided Cartesian componentwise and returns
   * <code>true</code> if they are equal, <code>false</code> otherwise.
   *
   * @param {Cartesian4} [right] The right hand side Cartesian.
   * @returns {boolean} <code>true</code> if they are equal, <code>false</code> otherwise.
   */
  public equals(right: ICartesian): boolean {
    return Cartesian4.equals(this, right)
  }

  /**
   * 将此笛卡尔坐标与提供的笛卡尔坐标逐个进行比较，并返回
   * <code>true</code> if they pass an absolute or relative tolerance test,
   * <code>false</code> otherwise.
   *
   * @param {Cartesian4} [right] The right hand side Cartesian.
   * @param {number} [relativeEpsilon=0] The relative epsilon tolerance to use for equality testing.
   * @param {number} [absoluteEpsilon=relativeEpsilon] The absolute epsilon tolerance to use for equality testing.
   * @returns {boolean} <code>true</code> if they are within the provided epsilon, <code>false</code> otherwise.
   */
  public equalsEpsilon(
    right: ICartesian,
    relativeEpsilon: number,
    absoluteEpsilon: number,
  ): boolean {
    return Cartesian4.equalsEpsilon(this, right, relativeEpsilon, absoluteEpsilon)
  }

  /**
   * Creates a string representing this Cartesian in the format '(x, y, z, w)'.
   *
   * @returns {string} A string representing the provided Cartesian in the format '(x, y, z, w)'.
   */
  public toString(): string {
    return `(${this.x}, ${this.y}, ${this.z}, ${this.w})`
  }

  //   // scratchU8Array and scratchF32Array are views into the same buffer
  //   public static readonly scratchF32Array = new Float32Array(1)
  //   public static readonly scratchU8Array = new Uint8Array(Cartesian4.scratchF32Array.buffer)

  //   public static readonly testU32 = new Uint32Array([0x11223344])
  //   public static readonly testU8 = new Uint8Array(Cartesian4.testU32.buffer)
  //   public static readonly littleEndian = Cartesian4.testU8[0] === 0x44

  /**
   * Packs an arbitrary floating point value to 4 values representable using uint8.
   *
   * @param {number} value A floating point number.
   * @param {Cartesian4} [result] The Cartesian4 that will contain the packed float.
   * @returns {Cartesian4} A Cartesian4 representing the float packed to values in x, y, z, and w.
   */
  public static packFloat(
    value: number,
    result?: ICartesian): ICartesian | undefined {
    //>>includeStart('debug', pragmas.debug);
    Check.typeOf.number('value', value)
    //>>includeEnd('debug');

    if (!defined(result)) {
      result = new Cartesian4()
    }

    // scratchU8Array and scratchF32Array are views into the same buffer
    scratchF32Array[0] = value

    if (littleEndian) {
      result!.x = scratchU8Array[0]
      result!.y = scratchU8Array[1]
      result!.z = scratchU8Array[2]
      result!.w = scratchU8Array[3]
    } else {
      // convert from big-endian to little-endian
      result!.x = scratchU8Array[3]
      result!.y = scratchU8Array[2]
      result!.z = scratchU8Array[1]
      result!.w = scratchU8Array[0]
    }
    return result
  }

  /**
   * Unpacks a float packed using public static packFloat.
   *
   * @param {Cartesian4} packedFloat A Cartesian4 containing a float packed to 4 values representable using uint8.
   * @returns {number} The unpacked float.
   * @private
   */
  public static unpackFloat(packedFloat: ICartesian): number {
    //>>includeStart('debug', pragmas.debug);
    Check.typeOf.object('packedFloat', packedFloat)
    //>>includeEnd('debug');

    // scratchU8Array and scratchF32Array are views into the same buffer
    if (littleEndian) {
      scratchU8Array[0] = packedFloat.x
      scratchU8Array[1] = packedFloat.y
      scratchU8Array[2] = packedFloat.z!
      scratchU8Array[3] = packedFloat.w!
    } else {
      // convert from little-endian to big-endian
      scratchU8Array[0] = packedFloat.w!
      scratchU8Array[1] = packedFloat.z!
      scratchU8Array[2] = packedFloat.y
      scratchU8Array[3] = packedFloat.x
    }
    return scratchF32Array[0]
  }

  public toQuaternion(): Quaternion {
    if (!defined(_car4_quaternion)) {
      throw new DeveloperError('quaternion is not defined.')
    }
    _car4_quaternion.x = this.x
    _car4_quaternion.y = this.y
    _car4_quaternion.z = this.z
    _car4_quaternion.w = this.w
    return _car4_quaternion
  }
} // Cartesian4 end
const _car4_quaternion = new Quaternion()
// scratchU8Array and scratchF32Array are views into the same buffer
const scratchF32Array = new Float32Array(1)
const scratchU8Array = new Uint8Array(scratchF32Array.buffer)

const testU32 = new Uint32Array([0x11223344])
const testU8 = new Uint8Array(testU32.buffer)
const littleEndian = testU8[0] === 0x44
